package com.example.utils;

import com.example.app.AppUtils;
import com.example.job.JobUtils;

import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * @Classname ClassScanUtils
 * @Description TODO
 * @Date 2022/5/24 18:22
 * @Created by XiongXiong
 * @Author: X.I.O
 */
public class ClazzScanUtils {

      private static ConcurrentHashMap<String,Object> cache = new ConcurrentHashMap<>();

      private static List<String> classPaths=new ArrayList<>();

      private static List<Class<?>> classList=new ArrayList<>();


    /**
     * 应用加载和重启专用
     * @param path
     * @param jarName
     */
      public static void onload(String path,String jarName){
            try {
                JarScanUtils.clear();
                Set<Class<?>> cls=JarScanUtils.loadAllJarFromAbsolute(path);
                List< Class< ? >> classes = new ArrayList<>();
                for (Class< ? > c : cls) {
                    classes.add(c);
                }
                boolean flag=AppUtils.isCanLoadJars(classes,jarName,path);
                if(flag){
                    System.out.println(path+"【合法应用, 开始加载】");
                    JarScanUtils.addAllSet(cls);
                    addClazz(classes);
                }else {
                    System.out.println(path+"【非合法应用, 加载失败】");
                    JarScanUtils.clear();
                    cls=null;
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }

        private static void addClazz(List<Class< ? >> classList){
            try {
                ObjectMaps.createClazzList(classList);
            }catch (Exception e){
                e.printStackTrace();
            }
        }

      public static void scanClass(Class<?> clazz) throws ClassNotFoundException {
        //包名
        String basePack = clazz.getPackage().getName();
        if(clazz.getResource("/")==null){
            return;
        }
        //先把包名转换为路径,首先得到项目的classpath
        String classpath = clazz.getResource("/").getPath();
        //然后把我们的包名basPach转换为路径名
        basePack = basePack.replace(".", File.separator);
        //然后把classpath和basePack合并
        String searchPath = classpath + basePack;
        doPath(new File(searchPath));
        //这个时候我们已经得到了指定包下所有的类的绝对路径了。我们现在利用这些绝对路径和java的反射机制得到他们的类对象
        for (String s : classPaths) {
            s = s.replace(classpath.replace("/","\\").replaceFirst("\\\\",""),"").replace("\\",".").replace(".class","");
            Class cls = Class.forName(s);
            classList.add(cls);
        }
      }
      /**
       * 该方法会得到所有的类，将类的绝对路径写入到classPaths中
       * @param file
       */
      private static void doPath(File file) {
        if (file.isDirectory()) {//文件夹
          //文件夹我们就递归
          File[] files = file.listFiles();
          for (File f1 : files) {
            doPath(f1);
          }
        } else {//标准文件
          //标准文件我们就判断是否是class文件
          if (file.getName().endsWith(".class")) {
            //如果是class文件我们就放入我们的集合中。
            classPaths.add(file.getPath());
          }
        }
      }

      public static List<Class<?>> getClassPaths(){
        return classList;
      }

      public static void searchClass(Class< ? > clazz) throws IOException, ClassNotFoundException {
            String basePack = clazz.getPackage().getName();
            //通过当前线程得到类加载器从而得到URL的枚举
            Enumeration<URL> urlEnumeration = Thread.currentThread().getContextClassLoader().getResources(basePack.replace(".", "/"));
            try {
                  while (urlEnumeration.hasMoreElements()) {
                    URL url = urlEnumeration.nextElement();//得到的结果大概是：jar:file:/C:/Users/ibm/.m2/repository/junit/junit/4.12/junit-4.12.jar!/org/junit
                    String protocol = url.getProtocol();//大概是jar
                    if ("jar".equalsIgnoreCase(protocol)) {
                      //转换为JarURLConnection
                      JarURLConnection connection = (JarURLConnection) url.openConnection();
                      if (connection != null) {
                        JarFile jarFile = connection.getJarFile();
                        if (jarFile != null) {
                          //得到该jar文件下面的类实体
                          Enumeration<JarEntry> jarEntryEnumeration = jarFile.entries();
                          while (jarEntryEnumeration.hasMoreElements()) {
                            JarEntry entry = jarEntryEnumeration.nextElement();
                            String jarEntryName = entry.getName();
                            //这里我们需要过滤不是class文件和不在basePack包名下的类
                            if (jarEntryName.contains(".class") && jarEntryName.replaceAll("/",".").startsWith(basePack)) {
                              String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replace("/", ".");
                              classPaths.add(className);
                              Class< ? > clsClass=Class.forName(className);
                              classList.add(clsClass);
                            }
                          }
                        }
                      }
                    }
              }
            }catch (Exception e){
              e.printStackTrace();
            }

      }
}
